lpunbfandomcom-20200214-history
Seminário Sobre Linguagem Lua 1/2014 - Kelvin William(11/0159560) e Bruno Ribeiro(11/0111141)
'Introdução' : Lua é uma linguagem de programação de extensão projetada para dar suporte à programação procedimental em geral com facilidades para a descrição de dados. Ela também oferece um bom suporte para programação orientada a objetos, programação funcional, e programação orientada a dados. Lua é planejada para ser usada como uma linguagem de script poderosa, leve, e embarcável por qualquer programa que necessite de uma. Lua é implementada como uma biblioteca, escrita em C puro, o subconjunto comum de C Padrão e C++. : Por ser uma linguagem de extensão, Lua não possui a noção de um programa "principal": ela somente funciona embarcada em um cliente hospedeiro, chamado de programa embarcante ou simplesmente de hospedeiro. O programa hospedeiro pode invocar funções para executar um pedaço de código Lua, pode escrever e ler variáveis Lua, e pode registrar funções C para serem chamadas por código Lua. Através do uso de funções C, Lua pode ser aumentada para lidar com uma variedade ampla de domínios diferentes, criando assim linguagens de programação personalizadas que compartilham um arcabouço sintático. A distribuição Lua inclui um exemplo de um programa hospedeiro chamado lua, o qual usa a biblioteca Lua para oferecer um interpretador Lua de linha de comando completo, para uso interativo ou em lote. Histórico Lua é inteiramente projetada, implementada e desenvolvida no Brasil, por uma equipe na PUC-RIO (Pontifícia Universidade Católica do Rio de Janeiro). Lua nasceu e cresceu no Tecgraf, o então Grupo de Tecnologia em Computação Gráfica da PUC-Rio. Atualmente, Lua é desenvolvida no laboratório LabLua do Departamento de Informática da PUC-Rio. Lua 1.0 Não chegou a ser lançada publicamente, porém foi vista rodando em 28 de Julho de 1993, e mais provavelmente alguns meses antes disso. Lua 1.1 Foi lançada em 8 de Julho de 1994, foi a primeira versão pública do Lua e foi descrito em um paper de uma conferência. Lua 1.1 já contou com poderosas construções para descrição de dados, sintaxe simples, e uma máquina virtual bytecode. Lua 1.1 esteve disponível livremente para fins acadêmicos. Lua 2.1 Lua 2.1 foi lançado em 07 de fevereiro de 1995. Suas principais novidades foram semântica extensível através fallbacks e suporte para programação orientada a objetos. Esta versão foi descrita em um artigo de jornal. Começando com Lua 2.1, Lua tornou-se disponível gratuitamente para todos os efeitos, incluindo os usos comerciais. Lua 2.2 Lua 2.2 foi lançado em 28 de novembro de 1995. Seus principais novidades foram cadeias longas de caracteres(strings longas), a interface de depuração, melhores stack tracebacks , sintaxe estendida para definição de função, coleta de lixo de funções e suporte para pipes. Lua 2.3 Lua 2.3 nunca foi lançado publicamente; ele só existiu como uma versão beta. Lua 2.4 Lua 2.4 foi lançado em 14 de maio de 1996. Suas principais novidades foram o compilador externo(Luac), uma interface de depuração estendida com ganchos, e o fallback "getglobal". Lua 2.5 Lua 2.5 foi lançado em 19 de novembro de 1996. Seus principais novos recursos eram o casamento de padrões de função e o vararg. Lua 3.0 Lua 3.0 foi lançado em 01 julho de 1997. Sua principal novidade foi método tag como um poderoso substituto para fallbacks. Lua 3.0 também introduziu auxlib, uma biblioteca para ajudar a escrever bibliotecas Lua e suporte para compilação condicional (caiu em Lua 4.0). Lua 3.1 Lua 3.1 foi lançado em 11 de julho, 1998. Seus principais novos recursos eram funções anônimas e fechamentos de função via "upvalues". (Lua 5.0 trouxe de escopo lexical pleno e'' upvalues'' caiu) Isso trouxe um sabor de programação funcional para Lua. Houve também suporte para múltiplos contextos globais, mas a API não foi totalmente reentrante (este teve que esperar até Lua 4.0). Lua 3.1 também passou por uma grande revisão de código, reorganização e limpeza, reduzindo assim a interdependência entre módulos. Lua 3.2 Lua 3.2 foi lançado em 08 de julho de 1999. Seus principais novidades foram a biblioteca de depuração e novas funções de tabela. O último lançamento foi Lua 3.2.2, lançado em 22 de fevereiro de 2000. Lua 4.0 Lua 4.0 foi lançada em 06 de novembro de 2000. Suas principais novidades foram múltiplos estados, uma nova API, declarações "for", e execução plena velocidade com informações de depuração completa. Além disso, Lua 4.0 já não tem funções built-in: todas as funções da biblioteca padrão são escritos usando a API oficial. O último lançamento foi Lua 4.0.1, lançado em 4 de julho de 2002. Lua 5.0 Lua 5.0 foi lançado em 11 de abril de 2003. Seus principais novidades foram multithreading colaborativo via coroutines Lua, de escopo lexical cheio em vez de upvalues e metatabelas em vez de tags e métodos de tag. Lua 5.0 também introduz booleanos, chamadas de cauda adequadas e tabelas fracas. Outras características são melhor suporte para pacotes, nova API para carregar pedaços de Lua, novo protocolo de tratamento de erros, melhores mensagens de erro, e muito mais. Lua 5.0 foi a primeira versão a ser lançado sob a nova licença. O último lançamento foi Lua 5.0.3, lançado em 26 de junho, 2006. Lua 5.1 Lua 5.1 foi lançado em 21 de fevereiro de 2006. Seus principais novidades foram um novo sistema de módulos, coleta de lixo incremental, novo mecanismo para varargs, nova sintaxe para cadeias longas de letras(strings) e comentários, os operadores mod e comprimento, metatabelas para todos os tipos, novo esquema de configuração via luaconf.h, e um analisador totalmente reentrante. O último lançamento foi Lua 5.1.5, lançado em 17 de fevereiro, 2012. Lua 5.2 Lua 5.2 foi lançado em 16 dezembro de 2011. Suas principais novidades são ceder pcall e metamétodos, novo sistema lexical para globals, tabelas efêmeras, nova biblioteca para operações bit a bit, as funções de luz C, coletor de lixo de emergência, goto e finalizadores para tabelas. A versão atual é Lua 5.2.3, lançado em 07 dezembro de 2013. Lua 5.3 Trabalho em Lua 5.3 já começou, mas não há nenhuma data de lançamento ainda. Se você quiser experimentá-lo agora, obter a versão mais recente trabalho. Por favor, note que todos os detalhes podem mudar na versão final. Características da Linguagem Lua é normalmente descrita como uma linguagem de múltiplos paradigmas, oferecendo um pequeno conjunto de características gerais que podem ser estendidas para encaixar diferentes tipos de problemas, em vez de fornecer uma especificação mais complexa e rígida para combinar com um único paradigma. Lua, por exemplo, não contém apoio explícito à herança, mas permite que ela seja executada com relativa facilidade com metatables. Do mesmo modo, Lua permite que programadores quando implementam nomes, classes, e outras funções, empreguem poderosas técnicas de programação funcional e completos escopos lexicais. Pontos Fortes: * Lua é linguagem estabelecida e robusta: Lua é usada em muitas aplicações industriais(e.g.,Adobe's Photoshop Lightroom),com ênfase em sistemas embutidos(e.g.,o middleware ''Ginga para TV digital) e jogos (e.g., World of Warcraft e Angry Birds). Lua é atualmente a linguagem de script mais usada em jogos. Lua tem um sólido manual de referência e existem vários livros sobre a linguagem. Várias versões de Lua foram lançadas e usadas em aplicações reais desde a sua criação em 1993. * '''Lua é rápida': Lua tem uma merecida reputação de ótimo desempenho. Outras linguagens de script aspiram ser "tão rápidas quanto Lua". Vários benchmarks mostram Lua como a linguagem mais rápida dentre as linguagens de script interpretadas. Lua é rápida não só em programas específicos para benchmarks, mas no dia-a-dia também. Porções substanciais de aplicações grandes são escritas em Lua. * Lua é portátil: Lua é distribuída via um pequeno pacote e compila sem modificações em todas as plataformas que têm um compilador C padrão. Lua roda em todos os tipos de Unix e Windows, e também em dispositivos móveis (usando Android, iOS, BREW, Symbian, Windows Phone), em microprocessadores embutidos (como ARM e Rabbit, para aplicações como Lego MindStorms), e até mainframes IBM. * Lua é embutível: Lua é uma engine rápida e pequena que você pode facilmente embutir na sua aplicação. Lua tem uma API simples e bem documentada que permite uma integração forte com código escrito em outras linguagens. É simples estender Lua com bibliotecas escritas em outras linguagens. Também é simples estender programas escritos em outras linguagens com Lua. Lua é usada para estender programas escritos não só em C e C++, mas também em Java, C#, Smalltalk, Fortran, Ada, Erlang, e mesmo outras linguagens de script, como Perl and Ruby. * Lua é poderosa (e simples): Um conceito fundamental no projeto de Lua é fornecer meta-mecanismos para a implementação de construções, em vez de fornecer uma multidão de construções diretamente na linguagem. Por exemplo, embora Lua não seja uma linguagem puramente orientada a objetos, ela fornece meta-mecanismos para a implementação de classes e herança. Os meta-mecanismos de Lua trazem uma economia de conceitos e mantêm a linguagem pequena, ao mesmo tempo que permitem que a semântica seja estendida de maneiras não convencionais. * Lua é pequena: Incluir Lua numa aplicação não aumenta quase nada o seu tamanho. O pacote de Lua 5.2.3, contendo o código fonte e a documentação, ocupa 246K comprimido e 960K descompactado. O fonte contém cerca de 20000 linhas de C. No Linux, o interpretador Lua contendo todas as bibliotecas padrões de Lua ocupa 182K e a biblioteca Lua ocupa 244K. * Lua é livre: Lua é software livre de código aberto, distribuída sob uma licença muito liberal (a conhecida licença MIT). Lua pode ser usada para quaisquer propósitos, incluindo propósitos comerciais, sem qualquer custo ou burocracia. Basta fazer um download e usá-la. * Lua tem importância global: O projeto e a evolução de Lua foram apresentados em 2007 na HOPL III, a 3a Conferência da ACM sobre a História das Linguagens de Programação. Essa conferência ocorre a cada 15 anos (a primeira foi em 1978 e a segunda em 1993) e somente poucas linguagens são apresentadas a cada vez. A escolha de Lua para a HOPL III é um importante reconhecimento do seu impacto mundial. Lua é a única linguagem de programação de impacto desenvolvida fora do primeiro mundo. Tipos de Dados Lua é uma linguagem dinamicamente tipada.Isso significa que variáveis não possuem tipos; somente valores possuem tipos. Não há definições de tipo na linguagem. Todos os valores carregam o seu próprio tipo. Todos os valores em Lua são valores de primeira classe. Isso significa que todos os valores podem ser guardados em variáveis, passados como argumentos para outras funções, e retornados como resultados. Há oito tipos básicos em Lua: nil, boolean, number, string, function, userdata, thread, e table. Nil é o tipo do valor nil, cuja propriedade principal é ser diferente de qualquer outro valor; ele geralmente representa a ausência de um valor útil. Boolean é o tipo dos valores false e true. Tanto nil como false tornam uma condição falsa; qualquer outro valor a torna verdadeira. Number representa tanto números inteiros como números reais (ponto flutuante de precisão dupla). String representa sequências imutáveis de bytes. Lua é 8 bits pura: cadeias podem conter qualquer valor de 8 bits, incluindo zeros ('\0') dentro delas. Lua pode chamar (e manipular) funções escritas em Lua e funções escritas em C. O tipo userdata é oferecido para permitir que dados C arbitrários sejam guardados em variáveis Lua. Um valor userdata é um ponteiro para um bloco de memória bruta. Há dois tipos de userdata: userdata completo, onde o bloco de memória é gerenciado por Lua, e userdata leve, onde o bloco de memória é gerenciado pelo hospedeiro. Userdata não possui operações pré-definidas em Lua, exceto atribuição e teste de identidade. Através do uso de metatabelas, o programador pode definir operações para valores userdata completos (veja §2.4). Valores userdata não podem ser criados ou modificados em Lua, somente através da API C. Isso garante a integridade de dados que pertencem ao programa hospedeiro. O tipo thread representa fluxos de execução independentes e é usado para implementar co-rotinas. Não confunda fluxos de execução Lua com processos leves do sistema operacional. Lua dá suporte a co-rotinas em todos os sistemas, até mesmo naqueles que não dão suporte a processos leves. O tipo table implementa arrays associativos, isto é, arrays que podem ser indexados não apenas com números, mas com qualquer valor Lua exceto nil e NaN (Not a Number, um valor numérico especial usado para representar resultados indefinidos ou não representáveis, tais como 0/0). Tabelas podem ser heterogêneas; isto é, elas podem conter valores de todos os tipos (exceto nil). Qualquer chave com valor nil não é considerada parte da tabela. De modo recíproco, qualquer chave que não é parte da tabela possui um valor nil associado. Tabelas são o único mecanismo de estruturação de dados em Lua; elas podem ser usadas para representar arrays comuns, sequências, tabelas de símbolos, conjuntos, registros, grafos, árvores, etc. Para representar registros, Lua usa o nome do campo como um índice. A linguagem dá suporte a essa representação fornecendo a.nome como açúcar sintático para a"nome". Há várias maneiras convenientes para criar tabelas em Lua. Usamos o termo sequência para denotar uma tabela onde o conjunto de todas as chaves numéricas positivas é igual a {1..} para algum inteiro n, que é chamado o comprimento da sequência. Assim como os índices, os valores dos campos de uma tabela podem ser de qualquer tipo. Em particular, por causa que funções são valores de primeira classe, campos de tabela podem conter funções. Portanto, tabelas podem também conter métodos. A indexação de tabelas segue a definição de igualdade primitiva na linguagem. As expressões ai e aj denotam o mesmo elemento da tabela se e somente se i e j são iguais primitivos (isto é, iguais sem metamétodos). Valores do tipo table, function, thread, e userdata (completo) são objetos: variáveis não contêm realmente esses valores, somente referências para eles. Atribuição, passagem de parâmetro, e retornos de função sempre manipulam referências para tais valores; essas operações não implicam em qualquer espécie de cópia. A função da biblioteca type retorna uma cadeia descrevendo o tipode um dado valor. Estruturas da Linguagem Conveções Léxicas Lua é uma linguagem de formato livre. Ela ignora espaços (incluindo quebras de linha) e comentários entre elementos léxicos (tokens), exceto como delimitadores entre nomes e palavras-chave. Nomes (também chamados de identificadores) em Lua podem ser qualquer cadeia de letras, dígitos, e sublinhados, que não iniciam com um dígito. Identificadores são usados para nomear variáveis, campos de tabelas, e rótulos. As seguintes palavras-chave são reservadas e não podem ser usadas como nomes: and break do else elseif end false for function goto if in local nil not or repeat return then true until while Lua é uma linguagem que diferencia minúsculas de maiúsculas: and é uma palavra reservada, mas And e AND são dois nomes válidos diferentes. Como uma convenção, nomes começando com um sublinhado seguido por letras maiúsculas (tais como _VERSION) são reservados para variáveis usadas por Lua. As seguintes cadeias denotam outros elementos léxicos: + - * / % ^ # ~= <= >= < > = ( ) { } [ ] :: ; : , . .. ... Cadeias literais podem ser delimitadas por aspas simples ou duplas balanceadas, e podem conter as seguintes sequências de escape similares às de C: '\a' (campainha), '\b' (retrocesso), '\f' (alimentação de formulário), '\n' (quebra de linha), '\r' (retorno de carro), '\t' (tabulação horizontal), '\v' (tabulação vertical), '\\' (barra invertida), '\"' (citação dupla), e '\'' (apóstrofo simples). Uma barra invertida seguida por uma quebra de linha de verdade resulta em uma quebra de linha na cadeia. A sequência de escape '\z' pula a extensão seguinte de caracteres de espaço em branco, incluindo quebras de linha; ela é particularmente útil para quebrar e identar uma cadeia de literais longa em múltiplas linhas sem adicionar as quebras de linha e espaços ao conteúdo da cadeia. Um byte em uma cadeia literal pode também ser especificado através de seu valor numérico. Isso pode ser feito com a sequência de escape \xXX, onde XX é uma sequência de exatamente dois dígitos hexadecimais, ou com a sequência de escape \ddd, onde ddd é uma sequência de até três dígitos decimais. (Note que se um escape decimal deve ser seguido por um dígito, ele deve ser expresso usando exatamente três dígitos.) Cadeias em Lua podem conter qualquer valor de 8 bits, incluindo zeros dentro delas, os quais podem ser especificados como '\0'. Cadeias literais podem também ser definidas usando um formato longo delimitado por colchetes longos. Definimos um colchete longo de abertura de nível n como um abre colchete seguido por n sinais de igual seguidos por outro abre colchete. Assim, um abre colchete longo de nível 0 é escrito como [um abre colchete longo de nível 1 é escrito como [=[, e assim por diante. Um colchete longo de fechamento é definido similarmente; por exemplo, um colchete longo de fechamento de nível 4 é escrito como ]. Um literal longo começa com um colchete longo de abertura de qualquer nível e termina no primeiro colchete longo de fechamento do mesmo nível. Ele pode conter qualquer texto exceto um colchete de fechamento do nível apropriado. Literais expressos dessa forma podem se estender por várias linhas, não interpretam nenhuma sequência de escape, e ignoram colchetes longos de qualquer outro nível. Qualquer tipo de sequência de fim de linha (retorno de carro, quebra de linha, retorno de carro seguido por quebra de linha, ou quebra de linha seguida por retorno de carro) é convertida em uma quebra de linha simples. Qualquer byte em uma cadeia literal que não é afetada explicitamente pelas regras anteriores representa ele mesmo. Contudo, Lua abre arquivos para parsing em modo texto, e as funções de arquivo do sistema podem ter problemas com alguns caracteres de controle. Assim, é mais seguro representar dados não-textuais como um literal entre aspas com sequências de escape explícitas para caracteres não-textuais. Por conveniência, quando o colchete longo de abertura é imediatamente seguido por uma quebra de linha, a quebra de linha não é incluída na cadeia. Como um exemplo, em um sistema usando ASCII (no qual 'a' é codificado como 97, a quebra de linha é codificada como 10, e '1' é codificado como 49), as cinco cadeias literais a seguir denotam a mesma cadeia: a = 'alo\n123"' a = "alo\n123\"" a = '\97lo\10\04923"' a = alo 123" a = [ [ alo 123"] ] Uma constante numérica pode ser escrita com um parte fracionária opcional e um expoente decimal opcional, marcado por uma letra 'e' ou 'E'. Lua também aceita constantes hexadecimais, as quais começam com 0x ou 0X. Constantes hexadecimais também aceitam uma parte fracionária opcional mais um expoente binário opcional, marcado por uma letra 'p' ou 'P'. Exemplos de contantes numéricas válidas são 3 3.0 3.1416 314.16e-2 0.31416E1 0xff 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1 Um comentário começa com um hífen duplo (--) em qualquer lugar fora de uma cadeia. Se o texto imediatamente após -- não é um colchete longo de abertura, o comentário é um comentário curto, que se estende até o fim da linha. Caso contrário, ele é um comentário longo, que se estende até o colchete longo de fechamento correspondente. Comentários longos são frequentemente usados para desabilitar código temporariamente. Variáveis Variáveis são lugares que guardam valores. Há três tipos de variáveis em Lua: variáveis globais, variáveis locais, e campos de tabelas. Um único nome pode denotar uma variável global ou uma variável local (ou um parâmetro formal de uma função, que é um tipo particular de variável local): var ::= Nome Nome denota identificadores, como definido anteriormente. Qualquer nome de variável é assumido ser global a menos que explicitamente declarado como um local. Variáveis locais possuem escopo léxico: variáveis locais podem ser acessadas livremente por funções definidas dentro do seu escopo (veja §3.5). Antes da primeira atribuição a uma variável, seu valor é nil. Colchetes são usados para indexar uma tabela: var ::= expprefixo ‘'['’ exp ‘']'’ O significado de acessos aos campos de uma tabela podem ser modificados por metatabelas. Um acesso a um variável indexada ti é equivalente a uma chamada gettable_event(t,i). A sintaxe var.Nome é apenas açúcar sintático para var"Nome": var ::= expprefixo ‘'.'’ Nome Um acesso a uma variável global x é equivalente a _ENV.x. Devido ao modo que um trecho é compilado, _ENV nunca é um nome global. Comandos Blocos Um bloco é uma lista de comandos, que são executados sequencialmente: bloco ::= {comando} Lua possui comandos vazios que permitem você separar comandos com ponto-e-vírgula, começar um bloco com um ponto-e-vírgula ou escrever dois ponto-e-vírgula em sequência: comando ::= ‘';'’ Chamadas de função e atribuições podem começar com um abre parêntese. Essa possibilidade leva a uma ambiguidade na gramática de Lua. Considere o seguinte fragmento: a = b + c (print or io.write)('done') A gramática poderia vê-lo de duas maneiras: a = b + c(print or io.write)('done') a = b + c; (print or io.write)('done') O parser corrente sempre vê tais construções da primeira maneira, interpretando o abre parêntese como o começo dos argumentos de uma chamada. Para evitar essa ambiguidade, é uma boa prática sempre preceder com um ponto-e-vírgula comandos que começam com um parêntese: ;(print or io.write)('done') Um bloco pode ser explicitamente delimitado para produzir um único comando: comando ::= do bloco end Blocos explícitos são úteis para controlar o escopo de declarações de variáveis. Blocos explícitos são também algumas vezes usados para adicionar um comando return no meio de outro bloco Trechos A unidade de compilação de Lua é chamada de um trecho. Sintaticamente, um trecho é simplesmente um bloco: trecho ::= bloco Lua trata um trecho como o corpo de uma função anônima com um número variável de argumentos. Dessa forma, trechos podem definir variáveis locais, receber argumentos, e retornar valores. Além disso, tal função anônima é compilada no escopo de uma variável local externa chamada _ENV. A função resultante sempre tem _ENV como seu único upvalue, mesmo se ele não usar essa variável. Um trecho pode ser armazenado em um arquivo ou em uma cadeia dentro do programa hospedeiro. Para executar um trecho, Lua primeiro pré-compila o trecho para instruções de uma máquina virtual, e então executa o código compilado com um interpretador para a máquina virtual. Trechos podem também ser pré-compilados para uma forma binária; veja o programa luac para detalhes. Programas na forma de código fonte e na forma compilada são intercambiáveis; Lua detecta automaticamente o tipo do arquivo e age de acordo. Atribuição Lua permite atribuições múltiplas. Por isso, a sintaxe para atribuição define uma lista de variáveis no lado esquerdo e uma lista de expressões no lado direito. Os elementos em ambas as listas são separados por vírgulas: comando ::= listavars ‘'='’ listaexps listavars ::= var {‘','’ var} listaexps ::= exp {‘','’ exp} Antes da atribuição, a lista de valores é ajustada para o comprimento da lista de variáveis. Se há mais valores do que o necessário, os valores em excesso são descartados. Se há menos valores do que o necessário a lista é estendida com tantos nil's quantos sejam necessários. Se a lista de expressões termina com uma chamada de função, então todos os valores retornados por essa chamada entram na lista de valores, antes do ajuste (exceto quando a chamada é delimitada por parênteses). O comando de atribuição primeiro avalia todas as suas expressões e somente então as atribuições são realizadas. Assim o código i = 3 i, ai = i+1, 20 atribui 20 a a3, sem afetar a4 porque o i em ai é avaliado (como 3) antes de receber 4. Similarmente, a linha x, y = y, x troca os valores de x e y, e x, y, z = y, z, x permuta de maneira cíclica os valores de x, y, e z. A semântica de atribuições para variáveis globais e campos de tabelas pode ser modificada por metatabelas. Uma atribuição a uma variável indexada ti = val é equivalente a settable_event(t,i,val). Uma atribuição a uma variável global x = val é equivalente à atribuição _ENV.x = val. Estruturas de Controle As estruturas de controle if, while, e repeat possuem o significado usual e a sintaxe familiar: comando ::= while exp do bloco end comando ::= repeat bloco until exp comando ::= if exp then bloco {elseif exp then bloco} [else bloco] end Lua também possui um comando for, em duas variações. A expressão da condição de uma estrutura de controle pode retornar qualquer valor. Tanto false quanto nil são considerados falso. Todos os valores diferentes de nil e false são considerados verdadeiro (em particular, o número 0 e a cadeia vazia são também verdadeiro). No laço repeat–'until', o bloco interno não termina na palavra chave until, mas somente após a condição. Assim, a condição pode se referir a variáveis locais declaradas dentro do corpo do laço. O comando goto transfere o controle do programa para um rótulo. Por razões sintáticas, rótulos em Lua são considerados comandos também: comando ::= goto Nome comando ::= rótulo rótulo ::= ‘'::'’ Nome ‘'::'’ Um rótulo é visível em todo o bloco onde ele é definido, exceto dentro de blocos aninhados onde um rótulo com o mesmo nome é definido e dentro de funções aninhadas. Um goto pode fazer um desvio para qualquer rótulo visível desde que ele não entre no escopo de uma variável local. Rótulos e comandos vazios são chamados de comandos nulos, uma vez que eles não realizam ações. O comando break termina a execução de um laço while, repeat, ou for, fazendo um desvio para o próximo comando após o laço: comando ::= break Um break termina o laço mais interno. O comando return é usado para retornar valores de uma função ou de um trecho (que é uma função disfarçada). Funções podem retornar mais do que um valor, assim a sintaxe para o comando return é comando ::= return listaexps [‘';'’] O comando return pode somente ser escrito como o último comando de um bloco. Se for realmente necessário um return no meio de um bloco, então um bloco interno explícito pode ser usado, como na expressão idiomática do return end, porque agora return é o último comando de seu bloco (interno). 'Comando For' O comando for possui duas formas: um numérica e outra genérica. O laço for numérico repete um bloco de código enquanto uma variável de controle varia de acordo com uma progressão aritmética. Ele tem a seguinte sintaxe: comando ::= for Nome ‘'='’ exp ‘','’ exp [‘','’ exp] do bloco end O bloco é repetido para nome começando com o valor da primeira exp, até que ele passe a segunda exp através de passos da terceira exp. Mais precisamente, um comando for como for v = e1, e2, e3 do bloco end é equivalente ao código: do local var, limite, passo = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limite and passo) then error() end while (passo > 0 and var <= limite) or (passo <= 0 and var >= limite) do local v = var bloco var = var + passo end end Note o seguinte: *Todas as três expressões de controle são avaliadas somente uma vez, antes do laço começar. Elas devem todas resultar em números. *var, limite, e passo são variáveis invisíveis. Os nomes mostrados aqui são para fins didáticos somente. *Se a terceira expressão (o passo) está ausente, então um passo de 1 é usado. *Você pode usar break para sair de um laço for. *A variável de laço v é local ao laço; você não pode usar o valor dela após o for terminar ou ser interrompido. Se você precisa desse valor, atribua-o a outra variável antes de interromper ou sair do laço. O comando for genérico funciona usando funções, chamadas de iteradores. A cada iteração, a função iteradora é chamada para produzir um novo valor, parando quando esse novo valor é nil. O laço for genérico tem a seguinte sintaxe: comando ::= for listanomes in listaexps do bloco end listanomes ::= Nome {‘','’ Nome} Um comando for como for var_1, ···, var_n in listaexps do bloco end é equivalente ao código: do local f, s, var = listaexps while true do local var_1, ···, var_n = f(s, var) if var_1 nil then break end var = var_1 bloco end end Note o seguinte: *listaexps é avaliada somente uma vez. Seus resultados são uma função iteradora, um estado, e um valor inicial para a primeira variável iteradora. *f, s, e var são variáveis invisíveis. Os nomes estão aqui para fins didáticos somente. *Você pode usar break para sair de um laço for. *As variáveis de laço var_i são locais ao laço; você não pode usar o valor delas após o for terminar. Se você precisa desses valores, então atribua-os a outras variáveis antes de interromper ou sair do laço. Subrotinas e outros elementos 'Definições de Funções' A sintaxe para uma definição de função é deffunção ::= função corpofunção corpofunção ::= ‘'('’ listapars ‘')'’ bloco end O seguinte açúcar sintático simplifica definições de funções: comando ::= function nomefunção corpofunção comando ::= local function Nome corpofunção nomefunção ::= Nome {‘'.'’ Nome} [‘':'’ Nome] O comando function f () corpo end é traduzido para f = function () corpo end O comando function t.a.b.c.f () corpo end é traduzido para t.a.b.c.f = function () corpo end O comando local function f () corpo end é traduzido para local f; f = function () corpo end não para local f = function () corpo end (Isso somente faz diferença quando o corpo da função contém referências para f.) Uma definição de função é uma expressão executável, cujo valor tem tipo function. Quando Lua pré-compila um trecho, todos os corpos de funções do trecho são pré-compilados também. Então, sempre que Lua executa a definição de uma função, a função é instanciada (ou fechada). Essa instância de função (ou fecho) é o valor final da expressão. Parâmetros agem como variáveis locais que são inicializadas com os valores dos argumentos: listapars ::= listanomes [‘','’ ‘'...'’] | ‘'...'’ Quando uma função é chamada, a lista de argumentos é ajustada para o comprimento da lista de parâmetros, a menos que a função seja uma função vararg, a qual é indicada por três pontos ('...') no fim de sua lista de parâmetros. Uma função vararg não ajusta sua lista de argumentos; ao invés disso, ela coleta todos os argumentos extras e os fornece à função através de uma expressão vararg, que também é denotada por três pontos. O valor desta expressão é uma lista de todos os argumentos extras de fato, similar a uma função com múltiplos resultados. Se uma expressão vararg é usada dentro de outra expressão ou no meio de uma lista de expressões, então sua lista de retorno é ajustada para um elemento. Se a expressão é usada como o último elemento de uma lista de expressões, então nenhum ajuste é feito (a menos que a última expressão esteja entre parênteses). Como um exemplo, considere as seguintes definições: function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end Em seguida, temos o seguinte mapeamento de argumentos para parâmetros e para expressões vararg: CHAMADA PARÂMETROS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 g(3) a=3, b=nil, ... --> (nada) g(3, 4) a=3, b=4, ... --> (nada) g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 g(5, r()) a=5, b=1, ... --> 2 3 Resultados são retornados usando o comando return (veja §3.3.4). Se o controle alcança o fim de uma função sem encontrar um comando return, então a função retorna sem nenhum resultado. Há um limite que depende do sistema para o número de valores que uma função pode retornar. Esse limite é garantidamente maior do que 1000. A sintaxe de dois pontos é usada para definir métodos, isto é, funções que possuem um parâmetro extra self implícito. Assim, o comando function t.a.b.c:f (params) corpo end é açúcar sintático para t.a.b.c.f = function (self, params) corpo end 'Regra de Visibilidade' Lua é uma linguagem com escopo léxico. O escopo de uma variável local começa no primeiro comando após a sua declaração e vai até o último comando não nulo do bloco mais interno que inclui a declaração. Considere o seguinte exemplo: x = 10 -- variável global do -- novo bloco local x = x -- novo 'x', com valor 10 print(x) --> 10 x = x+1 do -- outro bloco local x = x+1 -- outro 'x' print(x) --> 12 end print(x) --> 11 end print(x) --> 10 (o x global) Note que, em uma declaração como local x = x, o novo x sendo declarado não está no escopo ainda, e portanto o segundo x se refere a uma variável externa. Por conta das regras de escopo léxico, variáveis locais podem ser livremente acessadas por funções definidas dentro de seu escopo. Uma variável local usada por uma função mais interna é chamada de upvalue, ou de variável local externa, dentro da função mais interna. Note que cada execução de um comando local define novas variáveis locais. Considere o seguinte exemplo: a = {} local x = 20 for i=1,10 do local y = 0 ai = function () y=y+1; return x+y end end O laço cria dez fechos (isto é, dez instâncias da função anônima). Cada um desses fechos usa uma variável y diferente, enquanto todos eles compartilham o mesmo x. 'Tratamento de Erros' Internamente, Lua usa a facilidade longjmp de C para tratar erros. (Você pode também escolher usar exceções se você compilar Lua como C++; procure por LUAI_THROW no código fonte.) Quando Lua enfrenta qualquer erro (como um erro de alocação de memória, erros de tipo, erros sintáticos, e erros de tempo de execução) ela lança um erro; isto é, ela faz um desvio longo. Um ambiente protegido usa setjmp para estabelecer um ponto de recuperação; qualquer erro desvia para o ponto de recuperação ativo mais recente. Se um erro acontece fora de qualquer ambiente protegido, Lua chama uma função de pânico (veja lua_atpanic) e então chama abort, saindo portanto da aplicação hospedeira. Sua função de pânico pode evitar essa saída nunca retornando (e.g., fazendo um desvio longo para seu próprio ponto de recuperação fora de Lua). A função de pânico roda como se ela fosse um tratador de mensagens; em particular, a mensagem de erro está no topo da pilha. Contudo, não há garantias sobre o espaço da pilha. Para empilhar qualquer coisa na pilha, a função de pânico deve primeiro verificar o espaço disponível. A maioria das funções na API pode lançar um erro, por exemplo devido a um erro de alocação de memória. A documentação para cada função indica se ela pode lançar erros. Dentro de uma função C você pode lançar um erro chamando lua_error. 'I/O' A biblioteca de E/S oferece dois estilos diferentes para manipulação de arquivos. O primeiro usa descritores de arquivos implícitos; isto é, há operações para estabelecer um arquivo de entrada padrão e um arquivo de saída padrão, e todas as operações de entrada/saída são sobre esses arquivos padrão. O segundo estilo usa descritores de arquivos explícitos. Ao usar descritores de arquivos implícitos, todas as operações são fornecidas pela tabela io. Ao usar descritores de arquivos explícitos, a operação io.open retorna um descritor de arquivo e então todas as operações são fornecidas como métodos do descritor de arquivo. A tabela io também oferece três descritores de arquivos pré-definidos com seus significados usuais de C: io.stdin, io.stdout, e io.stderr. A biblioteca de E/S nunca fecha esses arquivos. A menos que dito de outra maneira, todas as funções de E/S retornam nil em caso de falha (mais uma mensagem de erro como um segundo resultado e um código de erro dependente do sistema como um terceiro resultado) e algum valor diferente de nil em caso de sucesso. Em sistemas não Posix, a computação da mensagem de erro e do código de erro em caso de erros pode não ser segura se há múltiplos fluxos de execução, pois ela depende da variável C global errno. 'MetaTabelas e Metamétodos' Todo valor em Lua pode ter uma metatabela. Essa metatabela é uma tabela Lua comum que define o comportamento do valor original sob certas operações especiais. Você pode mudar vários aspectos do comportamento de operações sobre um valor especificando campos específicos em sua metatabela. Por exemplo, quando um valor não numérico é o operando de uma adição, Lua verifica se há uma função no campo "__add" da metatabela do valor. Se ela acha uma, Lua chama essa função para realizar a adição. As chaves em uma metatabela são derivadas a partir dos nomes dos eventos; os valores correspondentes são chamados de metamétodos. No exemplo anterior, o evento é "add" e o metamétodo é a função que realiza a adição. Você pode consultar a metatabela de qualquer valor usando a função getmetatable. Você pode substituir a metatabela de tabelas usando a função setmetatable. Você não pode mudar a metatabela de outros tipos a partir de Lua (exceto usando a biblioteca de depuração); você deve usar a API C para isso. Tabelas e userdatas completos têm metatabelas individuais (embora múltiplas tabelas e userdatas possam compartilhar suas metatabelas). Valores de todos os outros tipos compartilham uma única metatabela por tipo; isto é, há uma única metatabela para todos os números, uma para todas as cadeias, etc. Por padrão, um valor não possui metatabela, mas a biblioteca de cadeias especifica uma metatabela para o tipo string. Uma metatabela controla como um objeto se comporta em operações aritméticas, comparações de ordem, concatenação, operação de comprimento, e indexação. Uma metatabela também pode definir uma função a ser chamada quando um userdata ou uma tabela são recolhidos pelo coletor de lixo. Quando Lua realiza uma dessas operações sobre um valor, ela verifica se esse valor possui uma metatabela com um evento correspondente. Se possui, o valor associado com aquela chave (o metamétodo) controla como Lua realizará a operação. 'Coleta de Lixo' Lua realiza gerenciamento automático de memória. Isso significa que você não precisa se preocupar com a alocação de memória para novos objetos nem com a liberação dela quando os objetos não são mais necessários. Lua gerencia memória automaticamente executando um coletor de lixo para coletar todos os objetos mortos (isto é, objetos que não são mais acessíveis a partir de Lua). Toda memória usada por Lua está sujeita ao gerenciamento automático: cadeias, tabelas, userdatas, funções, fluxos de execução, estruturas internas, etc. Lua implementa um coletor marca-e-varre (mark-and-sweep) incremental. Ele usa dois números para controlar seus ciclos de coleta de lixo: a pausa do coletor de lixo e o multiplicador de passo do coletor de lixo. Ambos usam pontos percentuais como unidades (e.g., um valor de 100 significa um valor interno de 1). A pausa do coletor de lixo controla quanto tempo o coletor espera antes de começar um novo ciclo. Valores maiores fazem o coletor ser menos agressivo. Valores menores do que 100 significam que o coletor não esperará para iniciar um novo ciclo. Um valor de 200 significa que o coletor espera a memória total em uso dobrar antes de iniciar um novo ciclo. O multiplicador de passo do coletor de lixo controla a velocidade relativa do coletor em relação à alocação de memória. Valores maiores fazem o coletor ser mais agressivo mas também aumentam o tamanho de cada passo incremental. Valores menores do que 100 tornam o coletor muito lento e podem fazer com que o coletor nunca termine um ciclo. O padrão é 200, o que significa que o coletor executa no "dobro" da velocidade de alocação de memória. Se você atribuir ao multiplicador de passo um número muito grande (maior do que 10% do número máximo de bytes que o programa pode usar), o coletor se comporta como um coletor pare-o-mundo. Se você então atribuir 200 à pausa, o coletor se comporta como em versões antigas de Lua, fazendo uma coleta completa toda vez que Lua dobra sua memória em uso. Você pode mudar esses números chamando lua_gc em C ou collectgarbage em Lua. Você pode também usar essas funções para controlar o coletor diretamente (e.g., pará-lo e reiniciá-lo). Como uma característica experimental em Lua 5.2, você pode mudar o modo de operação do coletor de incremental para generacional. Um coletor generacional assume que a maioria dos objetos morre jovem, e portanto ele percorre somente objetos jovens (criados recentemente). Esse comportamento pode reduzir o tempo usado pelo coletor, mas também incrementa o uso de memória (visto que objetos mortos velhos podem se acumular). Para mitigar esse segundo problema, de tempos em tempos o coletor generacional realiza uma coleta completa. Lembre-se que essa é uma característica experimental; você é bem-vindo a experimentá-la, mas verifique seus ganhos. 'Co-rotinas' Lua oferece suporte a co-rotinas, também chamadas de fluxos de execução múltiplos colaborativos. Uma co-rotina em Lua representa um fluxo de execução independente. Ao contrário de processos leves em sistemas que dão suporte a múltiplos fluxos de execução, contudo, uma co-rotina somente suspende sua execução através de uma chamada explícita a uma função de cessão. Você cria uma co-rotina chamando coroutine.create. Seu único argumento é uma função que é a função principal da co-rotina. A função create somente cria uma nova co-rotina e retorna uma referência para ela (um objeto do tipo thread); ela não inicia a co-rotina. Você executa uma co-rotina chamando coroutine.resume. Quando você chama coroutine.resume pela primeira vez, passando como seu primeiro argumento um fluxo de execução retornado por coroutine.create, a co-rotina inicia sua execução. na primeira linha de sua função principal. Argumentos extras passados para coroutine.resume são passados para a função principal da co-rotina. Após a co-rotina começar sua execução, ela executa até que termine ou ceda. Uma co-rotina pode terminar sua execução de duas maneiras: normalmente, quando sua função principal retorna (explicitamente ou implicitamente, após a última instrução); e anormalmente, se há um erro não protegido. No primeiro caso, coroutine.resume retorna true, mais quaisquer valores retornados pela função principal da co-rotina. Em caso de erros, coroutine.resume retorna false mais uma mensagem de erro. Uma co-rotina cede chamando coroutine.yield. Quando uma co-rotina cede, a coroutine.resume correspondente retorna imediatamente, mesmo se a cessão aconteceu dentro de chamadas de função aninhadas (isto é, não na função principal, mas em uma função diretamente ou indiretamente chamada pela função principal). No caso de uma cessão, coroutine.resume também retorna true, mais quaisquer valores passados para coroutine.yield. Da próxima vez que você reiniciar a mesma co-rotina, ela continua sua execução a partir do ponto onde ela cedeu, com a chamada a coroutine.yield retornando quaisquer argumentos extras passados para coroutine.resume. Como coroutine.create, a função coroutine.wrap também cria uma co-rotina, mas ao invés de retornar a própria co-rotina, ela retorna uma função que, quando chamada, reinicia a co-rotina. Quaisquer argumentos passados para essa função vão como argumentos extras para coroutine.resume. coroutine.wrap retorna todos os valores retornados por coroutine.resume, exceto o primeiro (o código booleano de erro). Ao contrário de coroutine.resume, coroutine.wrap não captura erros; qualquer erro é propagado para o chamador. Como um exemplo de como co-rotinas funcionam, considere o seguinte código: function foo (a) print("foo", a) return coroutine.yield(2*a) end co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) local r, s = coroutine.yield(a+b, a-b) print("co-body", r, s) return b, "end" end) print("main", coroutine.resume(co, 1, 10)) print("main", coroutine.resume(co, "r")) print("main", coroutine.resume(co, "x", "y")) print("main", coroutine.resume(co, "x", "y")) Quando você o executa, ele produz a seguinte saída: co-body 1 10 foo 2 main true 4 co-body r main true 11 -9 co-body x y main true 10 end main false cannot resume dead coroutine Você pode também criar e manipular co-rotinas através da API C: veja as funções lua_newthread, lua_resume, e lua_yield. Avaliação da Linguagem Avaliamos a linguagem segundo os critérios propostos no livro Conceitos de Lingugem de Programação, de Robert W. Sebesta. Inicialmente, avaliaremos os elementos que contribuem para cada uma das categorias. Simplicidade Global e Ortogonalidade Lua tem por premissa ser uma linguagem simples. Possui poucos tipos básicos e conjunto convencional (e pequeno) de estruturas de controle. Estes tornariam a linguagem simples, mas a ênfase em extensibilidade e a multiplicidade de paradigmas que podem ser alcançados pela linguagem fazem com que ela não seja tão simples (existem várias formas de se alcançar um mesmo resultado). Quanto à ortogonalidade, o fato de ser possível realizar atribuições múltiplas e receber retornos múltiplos já a tornam não tão ortogonal. Expressividade Possui grande poder de expressividade quando se trata de construir e manipular tabelas, já que estas são a principal estrutura da linguagem. Uma construção simples como: Opnames = {“+” = “add”, “-” = “sub”, “*” = “mul”, “/” = “div”} Pode levar diversas linhas em uma linguagem menos focada em tabelas. Atribuições e retornos múltiplos são pontos positivos neste critério. Abstração Tabelas já possibilitam um bom nível de abstração por si só. É possível pensar numa tabela como um objeto e funções definidas sobre ela como métodos. Por exemplo: Account = {balance = 0} Function Account.withdraw (v) Account.balance = Account.balance - v end Além disso, é possível imitar mecanismos típicos da programação orientada a objetos através de metatabelas. Tratamento de Exceções Lua não possui um suporte explícito para tratamento de excessões. Em vez disso, este tratamento deve ser feito através de chamadas protegidas (pcall). Exemplo: if pcall(funct) then -- Sem erros ao rodar 'funct' ... else – Tratamento de exceção ... end Conclusão A legibilidade da linguagem é fortemente afetada pela baixa simplicidade global e pela baixa ortogonalidade da linguagem, apesar das instruções de controle e seus tipos de dados e estruturas serem convenientes e da sua sintaxe ser simples. Por esta razão, concluimos que a linguagem tem baixa legibilidade. A capacidade de escrita, apesar da baixa simplicidade e ortogonalidade, é alta, uma vez que existe um grande suporte para abstração e uma grande expressividade na linguagem. A confiabilidade é baixa, já que a linguagem é dinamicamente tipada e não possui um suporte explícito para tratamento de exceções. Por fim, concluimos que o custo é moderado - o custo de treinamento é negativamente afetado pela baixa simplicidade, mas a capacidade de escrita torna o custo de escrever programas muito baixo. Os custos de compilação e de execução de um programa em Lua são os típicos em linguagens interpretadas, mas Lua leva uma pequena vantagem em relação às outras na execução. Referências Referências e Wiki http://lpunb.wikia.com/wiki/Seminário_Sobre_Linguagem_Lua_1/2014_-_Kelvin_Wil http://www.lua.org/about.html http://www.lua.org/versions.html http://pt.wikipedia.org/wiki/Lua_%28linguagem_de_programa%C3%A7%C3%A3o% http://en.wikipedia.org/wiki/Lua_%28programming_language%29 http://notebook.kulchenko.com/programming/lua-good-different-bad-and-ugly-parts http://www.inf.puc-rio.br/~roberto/talks/lua-evolution.pdf http://benchmarksgame.alioth.debian.org/u32/lua.php